﻿using Newtonsoft.Json;
using Org.BouncyCastle.Utilities;
using SqlSugar;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using Zocono.Infrastructure.Common;
using Zocono.WCS.Comm;
using Zocono.WCS.Domain.DomainRepository;
using Zocono.WCS.Domain.EntityInfo;
using Zocono.WCS.Domain.FSJDomain;
using Zocono.WCS.Domain.LogDomain;
using Zocono.WCS.Domain.PlcBytesObject;
using Zocono.WCS.Domain.PlcConnectPoolDomain;
using Zocono.WCS.Domain.ProcessModuleDomain;
using Zocono.WCS.Infrastructure.ApllicationDto.DtoWcsManage;
using Zocono.WCS.Infrastructure.ApllicationDto.WCSTaskDto;
using Zocono.WCS.WMSApiDomain.WebApi;

namespace Zocono.WCS.Domain.EquipmentProcessDomain.PlanarGeneralMessage
{
    /// <summary>
    /// 分选结果上报  组盘位 握手 2-0
    /// </summary>
    public class FSJWorker_ZuPan_2Service : IPlanarGeneralPlcActionProcessService
    {
        private readonly IRedisHelper _IRedisHelper;
        private readonly ILogUtil _LogUtil;
        private readonly IPlcConnectionPool _PlcConnectionPool;
        private readonly IWorkTaskInfoRepository _WorkTaskInfoRepository;
        private readonly IPlcWriteDbInfoRepository _PlcWriteDbInfoRepository;
        private readonly IPlcConnectionInfoRepository _PlcConnectionInfoRepository;
        private readonly IPlcPointInfoRepositpry _IPlcPointInfoRepositpry;
        private readonly IPlcConnectionStateInfoRepository _IPlcConnectionStateInfoRepository;
        private readonly IRunLogInfoService _IRunLogInfoService;
        private readonly IPlcReadDbInfoRepository _PlcReadDbInfoRepository;
        private readonly IInterfaceLogInfoService _InterfaceLogInfoService;
        private readonly IFSJMesService _IFSJMesService;

        public FSJWorker_ZuPan_2Service(IRedisHelper iRedisHelper, ILogUtil logUtil
            , IPlcConnectionPool plcConnectionPool
            , IWorkTaskInfoRepository workTaskInfoRepository
            , IPlcWriteDbInfoRepository plcWriteDbInfoRepository
            , IPlcConnectionInfoRepository plcConnectionInfoRepository,
            IPlcPointInfoRepositpry plcPointInfoRepositpry
             , IPlcConnectionStateInfoRepository plcConnectionStateInfoRepository
            , IRunLogInfoService runLogInfoService,
             IPlcReadDbInfoRepository plcReadDbInfoRepository,
             IInterfaceLogInfoService iterfaceLogInfoService,
            IFSJMesService iFSJMesService//,
                                         // AisleRequestService aisleRequestService
            )
        {
            _IRedisHelper = iRedisHelper;
            _LogUtil = logUtil;
            _PlcConnectionPool = plcConnectionPool;
            _WorkTaskInfoRepository = workTaskInfoRepository;
            _PlcWriteDbInfoRepository = plcWriteDbInfoRepository;
            _PlcConnectionInfoRepository = plcConnectionInfoRepository;
            _IPlcPointInfoRepositpry = plcPointInfoRepositpry;
            _IPlcConnectionStateInfoRepository = plcConnectionStateInfoRepository;
            _IRunLogInfoService = runLogInfoService;
            _PlcReadDbInfoRepository = plcReadDbInfoRepository;
            _InterfaceLogInfoService = iterfaceLogInfoService;
            _IFSJMesService = iFSJMesService;
        }

        public async Task ProcessActionMessageAsync(BytesObjectBase plcActionMessage, BytesObjectBase wcsActionMessage, EquipmentDbObject planarEquipmentDbObject/*, BytesObjectBase plcStateMassge*/)
        {
            /*
            * 业务需求：
            * 1.托盘进入分选机，分选机获取托盘的信息 调用wms接口 public async Task<ReturnContainer> GetContainerMsg(AutoSelectParaIn autoSelectParaIn)，获得电芯信息
            * 2.根据电芯条码，向MES获取电芯的详细信息（电芯电压，容量 等信息），托盘一到分选机托盘解绑
            * 3、根据电芯详情信息，和档位配置参数，进行分档，并把电芯分档信息写入plc
            * 4、机器人进行分选，托盘解绑，组盘绑定
            * 5、1）留在分选托盘的电芯入库；2）档位上的托盘满盘则留到下一个节点（NG档位走排出，复测档位走下个流程，正常档位流入库）
            * 6、组盘电芯上报到Mes

           /*
            * 处理逻辑
            * 1. 验证plc是否在线
            * 2. 验证当前设备是否报警
            * 3. 验证wcs任务，验证wcs当前子任务(待执行、执行中)，当前子任务已经是SC完成后更新了
            * 4. 组织plc报文，写入plc
            */

            var plcMessage = plcActionMessage as PlanarGeneralPlcActionBO;//Plc的动作报文
            var wcsMessage = wcsActionMessage as PlanarGeneralWcsActionBO;//Wcs的动作报文
            plcMessage.PalletBarcode = plcMessage.PalletBarcode.Trim();

            //TODO 提交分选结果数据上传Mes，后申请目标位置服务

            var ContainerBarcode = plcMessage.PalletBarcode.Trim();
            var EquipmentCode = plcMessage.EquipmentCode.Trim();
            
            var eqValue = _IRedisHelper.GetStringKey<string>($"PLC-WCS{plcMessage.EquipmentCode}");

            if (eqValue == null || string.IsNullOrEmpty(eqValue))
            {
                //_IRedisHelper.SetStringKey($"PLC-WCS{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(2));
                //交互位写入
                var objectType = typeof(PlanarGeneralWriteWcsAction).Name;
                var writeConfig = await _PlcWriteDbInfoRepository.GetFirstAsync(it => it.EquipmentCode == plcMessage.EquipmentCode && it.ObjectType == objectType);

                PlanarGeneralWriteWcsAction writeBo = new PlanarGeneralWriteWcsAction(
                    writeConfig.PlcConnectionId,
                    writeConfig.ID,
                    writeConfig.DbCode,
                    writeConfig.DbStart,
                    objectType,
                    plcMessage.EquipmentCode.ToInt32(),
                    0,
                    0,
                    0,
                    ContainerBarcode,
                    0,
                    0);

                RunLogInfo runLogInfo = new RunLogInfo();
                runLogInfo.ContainerBarcode = plcMessage.PalletBarcode;
                runLogInfo.EquipmentCode = plcMessage.EquipmentCode;
                runLogInfo.RunType = "分选台组盘";

                runLogInfo.RunLog = "分选台组盘任务开始";


                var plcConn = _PlcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID);
                if (plcConn == null)
                {
                    //runLogInfo.RunLog = $"获取连接({plcMessage.PlcConnectionID})失败";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【{plcMessage.EquipmentCode}】,连接池无连接({plcMessage.PlcConnectionID})");
                    return;
                }
                var plcIPStates = await _IPlcConnectionStateInfoRepository.GetFirstAsync(l => l.PlcConnectionID == plcMessage.PlcConnectionID && l.Connected == true);
                if (plcIPStates == null)
                {
                    //runLogInfo.RunLog = $"{plcConn.IP}plc已离线";
                    //await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                    _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【{plcMessage.EquipmentCode}】,获取连接({plcMessage.PlcConnectionID})失败");
                    return;
                }
                //if (plcMessage.AlrmCode != 0)
                //{
                //    runLogInfo.RunLog = $"报警,报警代码：{plcMessage.AlrmCode}";
                //    await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                //    return;
                //}
                //校验plc信息是否有托盘码
                if (string.IsNullOrEmpty(plcMessage.PalletBarcode) || plcMessage.PalletBarcode.Length != 10)
                {
                    writeBo.AlrmCode = 102;
                    writeBo.ActionType = 99;
                    var flag = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                    return;
                }
                //三楼矮盘分选位设备
                string[] floor3ai = { "310222", "310224", "310226", "310228", "310230" };
            
                //三楼高盘分选位设备
                string[] floor3gao = { "310284", "310286", "310288", "310290", "310292" };

                //一楼高盘分选位设备
                string[] floor1gao = { "110238", "110240", "110242", "110244" };

                var fenxTiaoxuan = "";
                //三楼矮盘分选位
                if (floor3ai.Contains(plcMessage.EquipmentCode))
                {
                    fenxTiaoxuan = "310232";
                }
                else if (floor3gao.Contains(plcMessage.EquipmentCode))
                {
                    fenxTiaoxuan = "320662";
                }
                else if (floor1gao.Contains(plcMessage.EquipmentCode))
                {
                    fenxTiaoxuan = "110246";
                }
                // TODO 20231129 去除NG挑选单电芯解绑操作
                //获取挑选位电芯为了防止 组盘位的时候 电芯在挑选位还未单电芯解绑以至于组盘位重新组盘MES报错
                //获取挑选位电芯为了防止 组盘位的时候 电芯在挑选位还未单电芯解绑以至于组盘位重新组盘MES报错
                //获取挑选位电芯为了防止 组盘位的时候 电芯在挑选位还未单电芯解绑以至于组盘位重新组盘MES报错
                var tiaoXuanDB = await _PlcReadDbInfoRepository.GetFirstAsync(it =>
                        it.DbCode == 1000 &&
                        it.EquipmentCode == "FX-" + fenxTiaoxuan
                    );

                if (tiaoXuanDB == null)
                {
                    _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】获取挑选位DB，PLC设备【FX-{plcMessage.EquipmentCode}】,获取组盘机电芯信息读DB失败！请配置分选挑选位电芯读DB");
                    return;
                }
                /////挑选位交互DB 拿到设备号
                var tiaoXuanDB101 = await _PlcReadDbInfoRepository.GetFirstAsync(it =>
                        it.DbCode == 101 && it.EquipmentCode == fenxTiaoxuan);
                PlanarGeneralPlcActionBO tiaoXuanEqBO = null;
                if (tiaoXuanDB101 != null)
                {
                    byte[] tiaoXuanDB101Bytes = await plcConn.ReadDbAsync(tiaoXuanDB101.DbCode, tiaoXuanDB101.DbStart, tiaoXuanDB101.DbLength);
                    if (tiaoXuanDB101Bytes != null)
                    {
                        tiaoXuanEqBO = new PlanarGeneralPlcActionBO();
                        tiaoXuanEqBO.Serialize(
                            tiaoXuanDB101.PlcConnectionID,
                            tiaoXuanDB101.ID,
                            tiaoXuanDB101.DbStart,
                            tiaoXuanDB101Bytes.Count(),
                            0,
                            tiaoXuanDB101.DbLength,
                            tiaoXuanDB101.ProcessModuleName,
                            tiaoXuanDB101.EquipmentCode,
                            tiaoXuanDB101Bytes
                        );
                    }
                }
                try
                {
                    byte[] tiaoXuanDBBytes = await plcConn.ReadDbAsync(tiaoXuanDB.DbCode, tiaoXuanDB.DbStart, tiaoXuanDB.DbLength);
                    if (tiaoXuanDBBytes != null)
                    {
                        //读取成功
                        PlanarGeneralPlcActionBOFx readPlcBarcode = new PlanarGeneralPlcActionBOFx();
                        readPlcBarcode.Serialize(
                            tiaoXuanDB.PlcConnectionID,
                            tiaoXuanDB.ID,
                            tiaoXuanDB.DbStart,
                            tiaoXuanDBBytes.Count(),
                            0,
                            tiaoXuanDB.DbLength,
                            tiaoXuanDB.ProcessModuleName,
                            tiaoXuanDB.EquipmentCode,
                            tiaoXuanDBBytes
                            );
                        _LogUtil.Debug($"分选台挑选位:读取电芯数据：【FX-{EquipmentCode}】-->" + JsonHelper.SerializeObject(readPlcBarcode));

                        WcsOkResultUploadInfo upInfo = new WcsOkResultUploadInfo();
                        upInfo.ContainerCode = plcMessage.PalletBarcode;
                        upInfo.EquipmentCode = plcMessage.EquipmentCode;
                        upInfo.TiaoXuanContainerCode = tiaoXuanEqBO?.PalletBarcode.Trim();
                        upInfo.TiaoXuanEquipmentCode = fenxTiaoxuan;
                        List<ContainerCellsMsgDto> cells = new List<ContainerCellsMsgDto>();

                        //List<BatteryUpDataDto> putInDatas = new List<BatteryUpDataDto>();
                        //封装上报数据
                        foreach (var item in readPlcBarcode.Infos)
                        {
                            if (!string.IsNullOrEmpty(item.code))
                            {
                                ContainerCellsMsgDto cell = new ContainerCellsMsgDto();
                                cell.CellPosttion = item.location.ToString();
                                cell.CellCode = item.code;
                                cells.Add(cell);
                            }
                        }
                        upInfo.CellDataDtos = cells;
                        //上报挑选完结果 单电芯解绑

                        var upDataResult = await WCSMessageWithWMSApi.WCSUploadNgResultAsync(upInfo);
                        _LogUtil.Debug($"分选台挑选位:上报挑选完毕：【FX-{EquipmentCode}】请求参数-->{JsonHelper.SerializeObject(upInfo)}--->返回结果：{JsonHelper.SerializeObject(upDataResult)}");

                        if (!upDataResult.Result)
                        {
                            writeBo.AlrmCode = 133;
                            writeBo.ActionType = 99;
                            var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                            _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                            _LogUtil.Error($"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台挑选位，PLC设备【FX-{plcMessage.EquipmentCode}】,读取分选机电芯数据失败！");
                            return;
                        }
                    }
                    else
                    {
                        writeBo.AlrmCode = 130;
                        writeBo.ActionType = 99;
                        var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                        _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                        _LogUtil.Error($"分选台挑选位：托盘【{plcMessage.PalletBarcode}】分选台挑选位，PLC设备【FX-{plcMessage.EquipmentCode}】,读取分选机电芯数据失败！");
                        return;
                    }
                }
                catch (Exception ex)
                {
                    writeBo.AlrmCode = 133;
                    writeBo.ActionType = 99;
                    var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                    _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘时挑选位单电芯解绑，PLC设备【FX-{plcMessage.EquipmentCode}】,分选台组盘时挑选位单电芯解绑={ex.Message}");
                    return;
                }
                //上报分选结果组盘
                //上报分选结果组盘
                //上报分选结果组盘
                //获取组盘位电芯信息
                //var objectTypeCell = typeof(PlanarGeneralPlcActionBOFx).Name;
                var barcodeDb = await _PlcReadDbInfoRepository
                        .GetFirstAsync(it =>
                        it.DbCode == 1000 &&
                        it.EquipmentCode == "FX-" + plcMessage.EquipmentCode
                    );
                if (barcodeDb == null)
                {
                    _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【FX-{plcMessage.EquipmentCode}】,获取组盘机电芯信息读DB失败！请配置分选组盘机电芯读DB");
                    return;
                }
                ////读取条码
                //var plcConn = _PlcConnectionPool.S7GetWritePlcConnection(plcMessage.PlcConnectionID);
                try
                {
                    byte[] barcodeBytes = await plcConn.ReadDbAsync(barcodeDb.DbCode, barcodeDb.DbStart, barcodeDb.DbLength);
                    if (barcodeBytes != null)
                    {
                        //读取成功
                        PlanarGeneralPlcActionBOFx readPlcBarcode = new PlanarGeneralPlcActionBOFx();
                        readPlcBarcode.Serialize(
                            barcodeDb.PlcConnectionID,
                            barcodeDb.ID,
                            barcodeDb.DbStart,
                            barcodeBytes.Count(),
                            0,
                            barcodeDb.DbLength,
                            barcodeDb.ProcessModuleName,
                            barcodeDb.EquipmentCode,
                            barcodeBytes
                            );
                        _LogUtil.Debug($"分选台组盘:读取电芯数据：【FX-{EquipmentCode}】-->" + JsonHelper.SerializeObject(readPlcBarcode));

                        List<BatteryUpDataDto> putInDatas = new List<BatteryUpDataDto>();
                        //封装上报数据
                        foreach (var item in readPlcBarcode.Infos)
                        {
                            if (!string.IsNullOrEmpty(item.code))
                            {
                                BatteryUpDataDto putInData = new BatteryUpDataDto();
                                putInData.EquipCode = EquipmentCode;
                                putInData.CellCode = item.code;
                                putInData.TrayCode = ContainerBarcode;
                                putInData.Position = item.location.ToString();
                                putInDatas.Add(putInData);
                            }
                        }
                        //请求分选机上传MES 分档结果
                        var upDataResult = await WCSMessageWithWMSApi.PostMesResultAsync(putInDatas, _InterfaceLogInfoService);
                        _LogUtil.Debug($"分选台组盘:上报组盘：【FX-{EquipmentCode}】请求参数-->{JsonHelper.SerializeObject(putInDatas)}--->返回结果：{JsonHelper.SerializeObject(upDataResult)}");

                        if (upDataResult.success)
                        {
                            writeBo.ActionType = plcMessage.ActionType;
                            var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                            if (res)
                            {
                                // 记录运行日志
                                runLogInfo.RunLog = $"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【{plcMessage.EquipmentCode}】分选台组盘任上报成功，写入报文成功！报文内容：{JsonConvert.SerializeObject(writeBo)}";
                                await _IRunLogInfoService.AddRunLogInfoAsync(runLogInfo);
                            }
                        }
                        else
                        {
                            writeBo.AlrmCode = 129;
                            writeBo.ActionType = 99;
                            var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                            _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                            _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【FX-{plcMessage.EquipmentCode}】,上报分选机组盘结果失败");
                        }
                    }
                    else
                    {
                        writeBo.AlrmCode = 130;
                        writeBo.ActionType = 99;
                        var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                        _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                        _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【FX-{plcMessage.EquipmentCode}】,读取分选机电芯数据失败！");
                        return;
                    }
                }
                catch (Exception ex)
                {
                    writeBo.AlrmCode = 131;
                    writeBo.ActionType = 99;
                    var res = await plcConn.WriteDbAsync(writeBo.DbCode, writeBo.DbStart, writeBo.Deserialize());
                    _IRedisHelper.SetStringKey($"PLC-{plcMessage.EquipmentCode}", plcMessage.EquipmentCode.ToString() + plcMessage.AlrmCode, TimeSpan.FromSeconds(10));
                    _LogUtil.Error($"分选台组盘：托盘【{plcMessage.PalletBarcode}】分选台组盘，PLC设备【FX-{plcMessage.EquipmentCode}】,上报电芯结果报错EX={ex.Message}");
                    return;
                }
            }
            

        }
    }
}
